using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Matrix.ServiceCommunication
{
    /// <summary>
    /// Matrix服务通信客户端接口
    /// 提供轻量级的服务间通信能力
    /// </summary>
    public interface IMatrixServiceClient
    {
        /// <summary>
        /// 创建HTTP客户端
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <returns>配置好的HTTP客户端</returns>
        HttpClient CreateClient(string serviceName);

        /// <summary>
        /// 创建带用户上下文的HTTP客户端
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="userContext">用户上下文信息</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>配置好的HTTP客户端</returns>
        Task<HttpClient> CreateClientAsync(string serviceName, UserContext? userContext = null, CancellationToken cancellationToken = default);

        /// <summary>
        /// 获取服务地址
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>服务地址URI</returns>
        Task<Uri> GetServiceAddressAsync(string serviceName, CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行GET请求
        /// </summary>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="serviceName">服务名称</param>
        /// <param name="path">请求路径</param>
        /// <param name="userContext">用户上下文</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应数据</returns>
        Task<TResponse?> GetAsync<TResponse>(
            string serviceName,
            string path,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行POST请求
        /// </summary>
        /// <typeparam name="TRequest">请求类型</typeparam>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="serviceName">服务名称</param>
        /// <param name="path">请求路径</param>
        /// <param name="request">请求数据</param>
        /// <param name="userContext">用户上下文</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应数据</returns>
        Task<TResponse?> PostAsync<TRequest, TResponse>(
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行PUT请求
        /// </summary>
        /// <typeparam name="TRequest">请求类型</typeparam>
        /// <typeparam name="TResponse">响应类型</typeparam>
        /// <param name="serviceName">服务名称</param>
        /// <param name="path">请求路径</param>
        /// <param name="request">请求数据</param>
        /// <param name="userContext">用户上下文</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应数据</returns>
        Task<TResponse?> PutAsync<TRequest, TResponse>(
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行DELETE请求
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="path">请求路径</param>
        /// <param name="userContext">用户上下文</param>
        /// <param name="cancellationToken">取消令牌</param>
        Task DeleteAsync(
            string serviceName,
            string path,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行自定义HTTP请求
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="request">HTTP请求消息</param>
        /// <param name="userContext">用户上下文</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>HTTP响应消息</returns>
        Task<HttpResponseMessage> SendAsync(
            string serviceName,
            HttpRequestMessage request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 批量获取服务实例地址
        /// </summary>
        /// <param name="serviceNames">服务名称列表</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>服务名称到地址的映射</returns>
        Task<Dictionary<string, Uri>> GetBatchServiceAddressesAsync(
            IEnumerable<string> serviceNames,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// 健康检查
        /// </summary>
        /// <param name="serviceName">服务名称</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>是否健康</returns>
        Task<bool> HealthCheckAsync(string serviceName, CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// 用户上下文信息
    /// </summary>
    public class UserContext
    {
        /// <summary>
        /// 用户ID
        /// </summary>
        public string? UserId { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        public string? UserName { get; set; }

        /// <summary>
        /// 租户ID
        /// </summary>
        public string? TenantId { get; set; }

        /// <summary>
        /// 请求ID
        /// </summary>
        public string? RequestId { get; set; }

        /// <summary>
        /// 链路追踪ID
        /// </summary>
        public string? TraceId { get; set; }

        /// <summary>
        /// 自定义属性
        /// </summary>
        public Dictionary<string, object?> Properties { get; set; } = new();

        /// <summary>
        /// 创建默认用户上下文
        /// </summary>
        public static UserContext Default => new UserContext();

        /// <summary>
        /// 创建带用户ID的上下文
        /// </summary>
        public static UserContext WithUserId(string userId) => new UserContext { UserId = userId };

        /// <summary>
        /// 创建带租户ID的上下文
        /// </summary>
        public static UserContext WithTenantId(string tenantId) => new UserContext { TenantId = tenantId };

        /// <summary>
        /// 创建完整用户上下文
        /// </summary>
        public static UserContext Create(string? userId = null, string? tenantId = null, string? requestId = null)
        {
            return new UserContext
            {
                UserId = userId,
                TenantId = tenantId,
                RequestId = requestId ?? Guid.NewGuid().ToString(),
                TraceId = System.Diagnostics.Activity.Current?.Id ?? Guid.NewGuid().ToString()
            };
        }
    }

    /// <summary>
    /// 服务通信扩展方法
    /// </summary>
    public static class MatrixServiceClientExtensions
    {
        /// <summary>
        /// 执行GET请求（无返回值）
        /// </summary>
        public static async Task GetAsync(
            this IMatrixServiceClient client,
            string serviceName,
            string path,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var httpClient = await client.CreateClientAsync(serviceName, userContext, cancellationToken);
            var response = await httpClient.GetAsync(path, cancellationToken);
            response.EnsureSuccessStatusCode();
        }

        /// <summary>
        /// 执行POST请求（无返回值）
        /// </summary>
        public static async Task PostAsync<TRequest>(
            this IMatrixServiceClient client,
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var httpClient = await client.CreateClientAsync(serviceName, userContext, cancellationToken);

            var json = System.Text.Json.JsonSerializer.Serialize(request);
            var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            var response = await httpClient.PostAsync(path, content, cancellationToken);
            response.EnsureSuccessStatusCode();
        }

        /// <summary>
        /// 执行PUT请求（无返回值）
        /// </summary>
        public static async Task PutAsync<TRequest>(
            this IMatrixServiceClient client,
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var httpClient = await client.CreateClientAsync(serviceName, userContext, cancellationToken);

            var json = System.Text.Json.JsonSerializer.Serialize(request);
            var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            var response = await httpClient.PutAsync(path, content, cancellationToken);
            response.EnsureSuccessStatusCode();
        }

        /// <summary>
        /// 带重试的服务调用
        /// </summary>
        public static async Task<TResponse?> GetWithRetryAsync<TResponse>(
            this IMatrixServiceClient client,
            string serviceName,
            string path,
            int maxRetries = 3,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            Exception? lastException = null;

            for (int i = 0; i <= maxRetries; i++)
            {
                try
                {
                    return await client.GetAsync<TResponse>(serviceName, path, userContext, cancellationToken);
                }
                catch (Exception ex) when (i < maxRetries)
                {
                    lastException = ex;
                    await Task.Delay(TimeSpan.FromMilliseconds(100 * (i + 1)), cancellationToken);
                }
            }

            throw lastException ?? new InvalidOperationException("服务调用失败");
        }
    }
}